/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package jwu2.addondb;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
import jwu2.core.Addon;
import jwu2.core.Site;
import jwu2.log.Logger;
import lombok.Cleanup;

/**
 *
 * @author Rolf
 */
public class AddonDB {
    private static final String filename = "JWU2AddonDB.dat";
    
    private List<AddonDBEntry> addons;
    
    private static AddonDB singleton;
    
    private AddonDB() {
        loadAddonDB();
    }
    
    public synchronized static AddonDB singleton() {
        if( singleton == null) {
            singleton = new AddonDB();
        }
        
        return singleton;
    }
    
    public synchronized AddonDBEntry checkForAddonDBEntry(String addonName) {
        for(AddonDBEntry entry : addons) {
            if( entry.getAddonName().toLowerCase().equals(addonName.toLowerCase()) ) {
                return entry;
            }
        }
        
        return null;
    }
    
    public synchronized void updateAddons(List<AddonDBEntry> updatedAddons) {
        for(AddonDBEntry newEntry : updatedAddons) {
            AddonDBEntry oldEntry = this.checkForAddonDBEntry(newEntry.getAddonName());
            
            //New addon, add to db
            if( oldEntry == null) {
                Logger.logln("New addon found: "+newEntry.getAddonName());
                
                addons.add(newEntry);
                newEntry.markAsUpdated();
            }
            
            //Entry already present
            else {
                for(Site s : newEntry.getSitesAvaliableFrom()) {
                    
                    //Check if this site was already known
                    boolean found = false;
                    for(Site s2 : oldEntry.getSitesAvaliableFrom()) {
                        if( s.equals(s2) ) {
                            found = true;
                            break;
                        }
                    }
                    
                    //Site not found, add to old entry
                    if( !found ) {
                        Logger.logln("New site found for addon: "+oldEntry.getAddonName()+" ["+s+"]");
                        oldEntry.addAddonAvaliableFromSite(newEntry.getAddonFromSite(s), s);
                        oldEntry.markAsUpdated();
                    }
                    
                    //Site already known, check versions
                    else {
                        //Check version of addon against new found version
                        if( newEntry.getAddonFromSite(s).isNewer(oldEntry.getAddonFromSite(s))) {
                            Logger.logln("Newer version found of addon: "+oldEntry.getAddonName()+" ["+s+"]");
                            oldEntry.addAddonAvaliableFromSite(newEntry.getAddonFromSite(s), s);
                            oldEntry.markAsUpdated();
                        }
                    }
                }
            }
        }
        
        saveAddonDB();
    }
    
    public synchronized void updateAddons(List<Addon> fetchedAddons, Site site) {
        for(Addon a : fetchedAddons) {
            AddonDBEntry oldEntry = this.checkForAddonDBEntry(a.getName());
            
            //New addon, add to db
            if( oldEntry == null) {
                AddonDBEntry newEntry = new AddonDBEntry(a.getName());
                newEntry.addAddonAvaliableFromSite(a, site);
                
                Logger.logln("New addon found: "+newEntry.getAddonName());
                
                addons.add(newEntry);
                newEntry.markAsUpdated();
            }
            
            //Entry already present
            else {
                //Check if this site was already known
                boolean found = false;
                for(Site s2 : oldEntry.getSitesAvaliableFrom()) {
                    if( site.equals(s2) ) {
                        found = true;
                        break;
                    }
                }

                //Site not found, add to old entry
                if( !found ) {
                    Logger.logln("New site found for addon: "+oldEntry.getAddonName()+" ["+site+"]");
                    oldEntry.addAddonAvaliableFromSite(a, site);
                    oldEntry.markAsUpdated();
                }

                //Site already known, check versions
                else {
                    //Check version of addon against new found version
                    if( a.isNewer(oldEntry.getAddonFromSite(site))) {
                        oldEntry.addAddonAvaliableFromSite(a, site);
                        Logger.logln("Newer version found of addon: "+oldEntry.getAddonName()+" ["+site+"]");
                        oldEntry.markAsUpdated();
                    }
                }
            }
        }
        
        saveAddonDB();
    }
    
    public synchronized List<AddonDBEntry> getFullAddonList() {
        return addons;
    }
    
    public synchronized List<AddonDBEntry> getAddonsUpdatedSince(long time) {
        List<AddonDBEntry> updatedAddons = new ArrayList<AddonDBEntry>();

        for(AddonDBEntry entry : addons) {
            if( entry.getLastUpdated() > time ) {
                updatedAddons.add(entry);
            }
        }
        
        return updatedAddons;
    }
    
    private synchronized void saveAddonDB() {
        try {
            @Cleanup ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename));
            
            out.writeObject(addons);
            out.flush();
        }
        catch(Exception e) {
            Logger.logln("Error saving addonDB: "+e);
        }
    }
    
    private synchronized void loadAddonDB() {
        try {
            @Cleanup ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
            
            addons = (List<AddonDBEntry>) in.readObject();
        }
        catch(Exception e) {
            Logger.logln("Error loading addonDB: "+e);
            addons = new ArrayList<AddonDBEntry>();
        }
    }
}
